import java.util.*;
import java.io.*;
import java.net.*;

abstract class Tcp {
    // 通信套接字
    protected Socket socket = null;

    public Tcp() {}

    static public ServerSocket newSrv(InetSocketAddress address) throws Exception {
        //创建TCP服务套接字
        ServerSocket srvSocket = new ServerSocket();
        //开启端口复用
        srvSocket.setReuseAddress(true);
        //绑定端口
        srvSocket.bind(address);

        return srvSocket;
    }

    public String recv() throws Exception {
        return new BufferedReader(new InputStreamReader(socket.getInputStream())).readLine();
    }

    public Tcp send(String data) throws Exception {
        OutputStream out = socket.getOutputStream();
        out.write(data.getBytes());
        return this;
    }

    public void quit() throws Exception {
        if (socket != null) {
            socket.close();
        }
        System.exit(0);
    }

    public abstract void run() throws Exception;
}

class TcpSrv extends Tcp {
    //存储服务套接字
    private ServerSocket srvSocket;
    private TcpChat chat;

    public TcpSrv(TcpChat chat) throws Exception {
        this.chat = chat;
        srvSocket = newSrv(new InetSocketAddress(chat.port));
    }

    public void quit() throws Exception {
        if (srvSocket != null) {
            srvSocket.close();
        }
        super.quit();
    }

    public void run() throws Exception {
        // System.out.printf("准备接受客户端的连接....\n");
        socket = srvSocket.accept();
        // System.out.printf("%s 客户端连接成功....\n", socket.getRemoteSocketAddress());
        new Thread(new ChatRecv(this, chat)).start();
        new ChatSend(this, chat).run();
    }
}

class TcpCli extends Tcp {
    private InetSocketAddress srvInfo = null;
    private TcpChat chat;

    public TcpCli(TcpChat chat) {
        this.chat = chat;
        socket = new Socket();
        srvInfo = new InetSocketAddress(chat.args[0], chat.port);
    }

    public void run() throws Exception {
        socket.connect(srvInfo);
        new Thread(new ChatRecv(this, chat)).start();
        new ChatSend(this, chat).run();
    }
}

class ChatRecv implements Runnable {
    private Tcp tcp = null;
    private TcpChat chat;

    public ChatRecv(Tcp tcp, TcpChat chat) {
        this.chat = chat;
        this.tcp = tcp;
    }

    public void run() {
        String s = null;

        try {
            while (true) {
                s = tcp.recv();
                if (s.equals("quit"))
                    break;
                chat.show("接受("+ tcp.socket.getRemoteSocketAddress() + "): " + s);
            }
            tcp.quit();
        } catch (Exception e) {}
    }
}

class ChatSend {
    private Tcp tcp = null;
    private Scanner sc = null;
    private TcpChat chat;

    public ChatSend(Tcp tcp, TcpChat chat) {
        this.tcp = tcp;
        this.chat = chat;
        sc = new Scanner(System.in);
    }

    public String getInput(String prompt) {
        System.out.printf(prompt);
        return sc.nextLine();
    }

    public void run() throws Exception {
        String input = null;
        while (true) {
            System.out.printf("\033[15;1H=========================\n\033[2K");
            input = getInput("发送: ");
            tcp.send(input + "\n");
            if (input.equals("quit"))
                break;
            chat.show("发送: " + input);
        }
        tcp.quit();
    }
}

public class TcpChat {
    public LinkedList<String> histroy = new LinkedList<String>();
    public int port = 9183;
    public String [] args = null;

    public TcpChat() {}

    public TcpChat(String [] args) {
        this.args = args;
    }

    public TcpChat(String [] args, int port) {
        this.args = args;
        this.port = port;
    }

    public synchronized void add(String s) {
        if (histroy.size() == 14) {
            histroy.remove();
        }
        histroy.add(s);
    }

    public void show(String s) {
        add(s);
        Iterator<String>  it = histroy.iterator();
        System.out.printf("\033[s\033[1;1H");
        while (it.hasNext()) {
            System.out.printf("\033[2K");
            System.out.println(it.next());
        }
        System.out.printf("\033[u");
    }

    static public void main(String [] args) {
        System.out.printf("\033[2J");
        try {
            if (args.length == 0) {
                new TcpSrv(new TcpChat()).run();
            } else {
                new TcpCli(new TcpChat(args)).run();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
